#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CodeBuddy最终登录测试脚本
基于发现的有效登录表单进行测试
"""

import requests
from urllib.parse import unquote, parse_qs, urlparse
import re
from bs4 import BeautifulSoup

class FinalLoginTest:
    def __init__(self):
        self.session = requests.Session()
        self.setup_headers()
        
    def setup_headers(self):
        """设置浏览器请求头"""
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
            "Accept-Encoding": "gzip, deflate, br",
            "DNT": "1",
            "Connection": "keep-alive",
            "Upgrade-Insecure-Requests": "1"
        })
    
    def get_login_form_from_openid_url(self):
        """从OpenID Connect URL获取登录表单"""
        print("🔐 从OpenID Connect URL获取登录表单...")
        
        # 这是测试中发现的有效URL
        openid_url = "https://www.codebuddy.ai/auth/realms/copilot/protocol/openid-connect/auth?client_id=console&redirect_uri=https%3A%2F%2Fwww.codebuddy.ai%2Fconsole&response_type=code"
        
        try:
            response = self.session.get(openid_url, allow_redirects=True)
            
            print(f"📊 状态码: {response.status_code}")
            print(f"🔗 最终URL: {response.url}")
            
            if response.status_code == 200:
                # 解析登录表单
                soup = BeautifulSoup(response.text, 'html.parser')
                
                # 查找登录表单
                login_form = soup.find('form', {'id': 'kc-form-login'})
                if not login_form:
                    # 查找任何包含用户名和密码字段的表单
                    forms = soup.find_all('form')
                    for form in forms:
                        username_field = form.find('input', {'name': re.compile(r'username|email')})
                        password_field = form.find('input', {'type': 'password'})
                        if username_field and password_field:
                            login_form = form
                            break
                
                if login_form:
                    action = login_form.get('action', '')
                    
                    # 处理相对URL
                    if action.startswith('/'):
                        base_url = f"{urlparse(response.url).scheme}://{urlparse(response.url).netloc}"
                        action = base_url + action
                    elif not action.startswith('http'):
                        action = response.url
                    
                    print(f"📝 找到登录表单，Action URL: {action}")
                    
                    # 获取所有表单字段
                    form_fields = {}
                    
                    # 获取隐藏字段
                    for hidden in login_form.find_all('input', {'type': 'hidden'}):
                        name = hidden.get('name')
                        value = hidden.get('value', '')
                        if name:
                            form_fields[name] = value
                            print(f"  隐藏字段: {name} = {value}")
                    
                    # 获取用户名字段名
                    username_field = login_form.find('input', {'name': re.compile(r'username|email')})
                    password_field = login_form.find('input', {'type': 'password'})
                    
                    if username_field and password_field:
                        username_field_name = username_field.get('name')
                        password_field_name = password_field.get('name')
                        
                        print(f"  用户名字段: {username_field_name}")
                        print(f"  密码字段: {password_field_name}")
                        
                        return {
                            'action': action,
                            'username_field': username_field_name,
                            'password_field': password_field_name,
                            'hidden_fields': form_fields
                        }
                    else:
                        print("❌ 未找到用户名或密码字段")
                else:
                    print("❌ 未找到登录表单")
                    
                    # 输出页面内容的一部分用于调试
                    print("\n📄 页面内容片段:")
                    print(response.text[:500] + "...")
                    
            else:
                print(f"❌ 请求失败，状态码: {response.status_code}")
                
        except Exception as e:
            print(f"❌ 获取登录表单失败: {e}")
            
        return None
    
    def perform_login_with_form(self, form_info):
        """使用表单信息执行登录"""
        print(f"\n🚀 执行登录到: {form_info['action']}")
        
        # 用户凭据
        username = "154hdgrkk7@dpmurt.my"
        password = "5gHpr0V!"
        
        print(f"👤 用户名: {username}")
        print(f"🔑 密码: {password}")
        
        # 准备登录数据
        login_data = form_info['hidden_fields'].copy()
        login_data[form_info['username_field']] = username
        login_data[form_info['password_field']] = password
        
        # 添加可能需要的额外字段
        if 'credentialId' not in login_data:
            login_data['credentialId'] = ''
        
        print(f"📋 提交的字段: {list(login_data.keys())}")
        
        # 设置登录请求头
        headers = {
            "Content-Type": "application/x-www-form-urlencoded",
            "Origin": f"{urlparse(form_info['action']).scheme}://{urlparse(form_info['action']).netloc}",
            "Referer": form_info['action'],
            "Cache-Control": "max-age=0",
            "Sec-Fetch-Dest": "document",
            "Sec-Fetch-Mode": "navigate",
            "Sec-Fetch-Site": "same-origin",
            "Sec-Fetch-User": "?1"
        }
        
        try:
            # 发送登录请求
            response = self.session.post(
                form_info['action'],
                data=login_data,
                headers=headers,
                allow_redirects=True,
                timeout=30
            )
            
            print(f"\n📊 登录响应:")
            print(f"  状态码: {response.status_code}")
            print(f"  最终URL: {response.url}")
            print(f"  响应长度: {len(response.text)} 字符")
            
            return self.analyze_final_result(response)
            
        except Exception as e:
            print(f"❌ 登录请求失败: {e}")
            return False
    
    def analyze_final_result(self, response):
        """分析最终登录结果"""
        print("\n🔍 分析登录结果...")
        
        final_url = response.url.lower()
        response_text = response.text.lower()
        
        print(f"🔗 最终URL: {response.url}")
        
        # 详细的成功/失败判断
        success_indicators = []
        failure_indicators = []
        
        # URL分析
        if "console" in final_url:
            success_indicators.append("URL包含console")
        if "account" in final_url:
            success_indicators.append("URL包含account")
        if "dashboard" in final_url:
            success_indicators.append("URL包含dashboard")
        if "error" in final_url:
            failure_indicators.append("URL包含error")
        if "login" in final_url and "action" in final_url:
            failure_indicators.append("仍在登录页面")
        
        # 内容分析
        if "welcome" in response_text:
            success_indicators.append("内容包含welcome")
        if "logout" in response_text:
            success_indicators.append("内容包含logout")
        if "invalid" in response_text:
            failure_indicators.append("内容包含invalid")
        if "incorrect" in response_text:
            failure_indicators.append("内容包含incorrect")
        if "error" in response_text:
            failure_indicators.append("内容包含error")
        
        # HTTP状态码
        if response.status_code == 200:
            success_indicators.append("HTTP 200状态码")
        elif response.status_code >= 400:
            failure_indicators.append(f"HTTP {response.status_code}错误")
        
        print(f"✅ 成功指标 ({len(success_indicators)}):")
        for indicator in success_indicators:
            print(f"  - {indicator}")
        
        print(f"❌ 失败指标 ({len(failure_indicators)}):")
        for indicator in failure_indicators:
            print(f"  - {indicator}")
        
        # 显示cookies
        self.display_session_info()
        
        # 最终判断
        if len(success_indicators) > len(failure_indicators) and response.status_code == 200:
            print("\n🎉 登录成功！")
            return True
        elif len(failure_indicators) > 0:
            print("\n❌ 登录失败")
            self.extract_error_details(response)
            return False
        else:
            print("\n⚠️ 登录状态不确定")
            return None
    
    def display_session_info(self):
        """显示session信息"""
        print(f"\n🍪 Session信息:")
        if self.session.cookies:
            print(f"  获取到 {len(self.session.cookies)} 个cookies:")
            for cookie in self.session.cookies:
                print(f"    - {cookie.name}: {cookie.value[:30]}...")
        else:
            print("  未获取到cookies")
    
    def extract_error_details(self, response):
        """提取详细错误信息"""
        print("\n🔍 错误详情:")
        
        try:
            soup = BeautifulSoup(response.text, 'html.parser')
            
            # 查找Keycloak特定的错误信息
            error_elements = soup.find_all(['div', 'span', 'p'], 
                                         class_=re.compile(r'alert|error|message|notification'))
            
            if error_elements:
                for element in error_elements[:3]:  # 只显示前3个
                    error_text = element.get_text().strip()
                    if error_text and len(error_text) < 300:
                        print(f"  ❌ {error_text}")
            else:
                # 查找可能的错误文本
                if "invalid" in response.text.lower():
                    print("  ❌ 可能的凭据错误")
                if "expired" in response.text.lower():
                    print("  ❌ 可能的session过期")
                    
        except Exception as e:
            print(f"  ❌ 提取错误信息失败: {e}")
    
    def test_authenticated_access(self):
        """测试认证后的访问"""
        print("\n🔐 测试认证后访问...")
        
        test_urls = [
            "https://www.codebuddy.ai/console",
            "https://www.codebuddy.ai/console/accounts"
        ]
        
        for url in test_urls:
            try:
                response = self.session.get(url, allow_redirects=True, timeout=10)
                print(f"📊 {url}")
                print(f"  状态码: {response.status_code}")
                print(f"  最终URL: {response.url}")
                
                if response.status_code == 200 and "login" not in response.url.lower():
                    print(f"  ✅ 可以访问")
                    return True
                else:
                    print(f"  ❌ 无法访问")
                    
            except Exception as e:
                print(f"  ❌ 测试失败: {e}")
        
        return False
    
    def run_final_test(self):
        """运行最终登录测试"""
        print("=" * 60)
        print("🎯 CodeBuddy最终登录测试")
        print("=" * 60)
        
        # 步骤1: 获取登录表单
        form_info = self.get_login_form_from_openid_url()
        if not form_info:
            print("❌ 无法获取登录表单，测试终止")
            return False
        
        # 步骤2: 执行登录
        login_result = self.perform_login_with_form(form_info)
        
        # 步骤3: 测试认证访问
        if login_result:
            auth_result = self.test_authenticated_access()
            if auth_result:
                print("\n🎉 完整登录流程成功！")
                return True
        
        print("\n❌ 登录测试失败")
        return False

def main():
    """主函数"""
    print("🚀 开始CodeBuddy最终登录测试...")
    
    tester = FinalLoginTest()
    success = tester.run_final_test()
    
    print("\n" + "=" * 60)
    print("📋 最终测试结果")
    print("=" * 60)
    
    if success:
        print("✅ 登录测试成功！")
        print("🎯 结论: 提供的用户凭据可以成功登录CodeBuddy")
    else:
        print("❌ 登录测试失败！")
        print("🎯 结论: 无法使用提供的凭据登录，可能原因:")
        print("  1. 用户名或密码不正确")
        print("  2. 账户被锁定或禁用")
        print("  3. 需要额外的验证步骤")
        print("  4. 网站有反自动化保护")
    
    print("\n💡 关于原始fetch请求:")
    print("  原始fetch请求失败的原因是URL参数过期")
    print("  但通过获取新的有效参数，登录是可能的")

if __name__ == "__main__":
    main()